#include "xmppcore/stream.h"

#include <QtCore/QXmlStreamReader>
#include <QtCore/QVector>

namespace yoohoo_xmppcore {

Stream::Stream() {
	_from = 0;
	_to = 0;
	_version = "1.0";
}

Stream::~Stream() {
	delete _from;
	delete _to;
}

QString Stream::toXml() {
	Q_CHECK_PTR(_to);
	Q_ASSERT(_version == "1.0");

	QString xml = "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'";

	if (_from != 0) {
		xml.append(" from='").append(_from->toString()).append('\'');
	}

	xml.append(" to='").append(_to->toString()).append('\'');

	if (_xmlLang.size() > 0) {
		xml.append(QString(" xml:lang='%1'").arg(_xmlLang));
	}

	xml.append(QString(" version='%1'>").arg(_version));

	return xml;
}

bool Stream::fromXml(const QString& xml) {
	QXmlStreamReader reader(xml);
	reader.readNext(); // start document

	reader.readNext(); // start element
	if (reader.hasError() || !reader.isStartElement())
		return false;

	if (reader.name().toString() != "stream" && reader.prefix().toString() != "stream")
		return false;

	QXmlStreamNamespaceDeclarations namespaceDescriptions = reader.namespaceDeclarations();

	if (namespaceDescriptions.size() != 2 && namespaceDescriptions.size() != 3)
		return false;

	QVectorIterator<QXmlStreamNamespaceDeclaration> namespaceDescriptionsIterator(namespaceDescriptions);
	while (namespaceDescriptionsIterator.hasNext()) {
		QXmlStreamNamespaceDeclaration namespaceDescription = namespaceDescriptionsIterator.next();

		QString prefix = namespaceDescription.prefix().toString();
		QString namespaceUri = namespaceDescription.namespaceUri().toString();
		if (prefix.size() == 0) { // default namespace
			if (namespaceUri != "jabber:client")
				return false;
		} else if (prefix == "stream") { // stream namespace
			if (namespaceUri != "http://etherx.jabber.org/streams")
				return false;
		} else {
			if (prefix != "xml")
				return false;
		}
	}

	QVectorIterator<QXmlStreamAttribute> attributesIterator(reader.attributes());
	while (attributesIterator.hasNext()) {
		QXmlStreamAttribute attribute = attributesIterator.next();

		QString prefix = attribute.prefix().toString();
		QString name = attribute.name().toString();

		if (prefix.size() == 0) { // default namespace
			if (name == "from") {
				_from = new JabberId;
				QString jidString = attribute.value().toString();
				if (!_from->fromString(jidString))
					return false;
			} else if (name == "to") {
				_to = new JabberId;
				QString jidString = attribute.value().toString();
				if (!_to->fromString(jidString))
					return false;
			} else if (name == "version") {
				_version = attribute.value().toString();
			} else if (name == "id") {
				_id = attribute.value().toString();
			} else {
				return false; // unknown attribute
			}
		} else if (prefix == "xml") {
			if (name != "lang") // must be xml:lang
				return false;

			_xmlLang = attribute.value().toString();
		} else { // unknown namespace
			return false;
		}

	}

	return true;
}

bool Stream::matches(const QString& xml) {
	return xml.startsWith("<stream:stream ");
}

XmppElement::ElementType Stream::elementType() const {
	return XmppElement::ElementTypeStream;
}

void Stream::setFrom(JabberId from) {
	if (_from !=0)
		delete _from;

	_from = new JabberId(from);
}

JabberId* Stream::from() {
	return _from;
}

void Stream::setTo(JabberId to) {
	if (_to != 0)
		delete _to;

	_to = new JabberId(to);
}

JabberId* Stream::to() {
	return _to;
}

void Stream::setId(QString id) {
	_id = id;
}

QString Stream::id() {
	return _id;
}

void Stream::setVersion(QString version) {
	_version = version;
}

QString Stream::version() {
	return _version;
}

void Stream::setXmlLang(QString xmlLang) {
	_xmlLang = xmlLang;
}

QString Stream::xmlLang() {
	return _xmlLang;
}

}
